/*
 * Copyright (c) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <hi_task.h>
#include <string.h>
#include <stdio.h>
#include "iot_config.h"
#include "iot_log.h"
#include "iot_main.h"
#include "iot_profile.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "app_demo_multi_sample.h"
#include "app_demo_config.h"
#include "wifi_connecter.h"

/* attribute initiative to report */
#define TAKE_THE_INITIATIVE_TO_REPORT
/* oc request id */
#define CN_COMMADN_INDEX                    "commands/request_id="
/* oc report HiSpark attribute */
#define IO_FUNC_GPIO_OUT 0
#define IOT_GPIO_INDEX_10 10                //普通输出口，控制交通灯，位0
#define IOT_GPIO_INDEX_11 11                //普通输出口，控制交通灯，位1
#define IOT_GPIO_INDEX_12 12                //普通输出口，控制交通灯，位2
#define TRAFFIC_LIGHT_CMD_PAYLOAD           "led_value"
#define TRAFFIC_LIGHT_CMD_CONTROL_MODE      "ControlModule"
#define TRAFFIC_LIGHT_CMD_AUTO_MODE         "AutoModule"
#define TRAFFIC_LIGHT_SERVICE_ID_PAYLOAD    "TrafficLight"

#define STRAIGHT_NORTH_SOUTH_GREEN          "TimerSNSG"
#define STRAIGHT_NORTH_SOUTH_YELLOW         "STRA_NS_YELLOW"
#define STRAIGHT_EAST_WEST_GREEN            "TimerSEWG"
#define STRAIGHT_EAST_WEST_YELLOW           "STRA_EW_YELLOW"

#define TASK_SLEEP_1000MS (1000)
#define TASK_SLEEP_500MS (500)

extern int Timer_Stra_NS_G;
extern int Timer_Stra_NS_Y;
extern int Timer_Stra_EW_G;
extern int Timer_Stra_EW_Y;

int Timer_Stra_NS_G_remote = 10;
int Timer_Stra_NS_Y_remote = 3;
int Timer_Stra_EW_G_remote = 10;
int Timer_Stra_EW_Y_remote = 3;

extern int Timer_Stra_NS_G_Auto;
extern int Timer_Stra_EW_G_Auto;

unsigned char auto_count_flag = 0;          //自动控制模式计时标志位
unsigned char Msg_Cmd_change = 0;           //远程控制模式指令下发标志位

/*交通灯应用程序设置函数*/
void TrafficLightAppOption(HiTrafficLightMode appOptionMode, HiControlModeType appOptionType)
{
    unsigned char currentMode = 0;

    currentMode = SetKeyStatus(appOptionMode);              //将模式设置为 currentMode
    
    switch (GetKeyStatus(CURRENT_MODE))                     //向云端回报当前的模式
    {
        case TRAFFIC_CONTROL_MODE:
            TrafficLightStatusReport(TRAFFIC_CONTROL_MODE, SetupTrflControlModule);
            break;
        case TRAFFIC_AUTO_MODE:
            TrafficLightStatusReport(TRAFFIC_AUTO_MODE, SetupTrflAutoModule);
            break;
        default:
            break;
    }
}

/* 对接收到的云端发送过来的消息进行处理的函数 */
static void TrafficLightMsgRcvCallBack(char *payload)            //payload就是消息指针
{
    unsigned char currentMode = 0;
    unsigned char currentType = 0;
    IOT_LOG_DEBUG("PAYLOAD:%s\r\n", payload);

    /*收到Control模式指令*/
    if (strstr(payload, TRAFFIC_LIGHT_CMD_CONTROL_MODE) != NULL) //在消息中找到相应指令的关键词
    {                                                            
        currentMode = SetKeyStatus(TRAFFIC_CONTROL_MODE);
        auto_count_flag = 1;
        Msg_Cmd_change = 1;

        int number_temp = 0;
        int number_str = 0;

        if (strstr(payload, STRAIGHT_NORTH_SOUTH_GREEN) != NULL)                // 南北向直行绿灯，‘00’
        { 
            currentType = SetKeyType(STRA_NS_GREEN);
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   //IOT_GPIO_VALUE0是开启
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   //IOT_GPIO_VALUE0是低电平
            
            for (unsigned char i = 0; i < 5; i++)           //处理消息中的时间指令信息
            {
                number_str = *(payload + 22 + i);           //第22位开始是时间值
                if (number_str >= 48 && number_str <= 57)
                {
                    if(i == 0)                              //如果是一位数
                    {
                        number_temp = number_str - 48;
                        Timer_Stra_NS_G_remote = number_temp;
                    }
                    else                                    //如果是多位数，目前限定两位数
                    {
                        number_temp = (number_temp * 10) +(number_str - 48);
                        Timer_Stra_NS_G_remote = number_temp;
                    }
                }
                else
                {
                    break;
                }
            }
        }

        else if (strstr(payload, STRAIGHT_NORTH_SOUTH_YELLOW) != NULL)          // 南北向直行黄灯，‘01’
        {
            currentType = SetKeyType(STRA_NS_YELLOW); 
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);  
        }

        else if (strstr(payload, STRAIGHT_EAST_WEST_GREEN) != NULL)             // 东西向直行绿灯，‘10’
        {
            currentType = SetKeyType(STRA_EW_GREEN); 
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE0, IO_FUNC_GPIO_OUT);

            for (unsigned char i = 0; i < 5; i++)
            {
                number_str = *(payload + 22 + i);
                if (number_str >= 48 && number_str <= 57)
                {
                    if(i == 0)
                    {
                        number_temp = number_str - 48;
                        Timer_Stra_EW_G_remote = number_temp;
                    }
                    else
                    {
                        number_temp = (number_temp * 10) +(number_str - 48);
                        Timer_Stra_EW_G_remote = number_temp;
                    }
                }
                else
                {
                    break;
                }
            }
        }

        else if (strstr(payload, STRAIGHT_EAST_WEST_YELLOW) != NULL)            // 东西向直行黄灯，‘11’
        {
            currentType = SetKeyType(STRA_EW_YELLOW); 
            GpioControl(IOT_GPIO_INDEX_10, IOT_GPIO_INDEX_10,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);   
            GpioControl(IOT_GPIO_INDEX_11, IOT_GPIO_INDEX_11,                   
                        IOT_GPIO_DIR_OUT, IOT_GPIO_VALUE1, IO_FUNC_GPIO_OUT);
        }
    } 
    
    /*收到Auto模式指令*/
    else if (strstr(payload, TRAFFIC_LIGHT_CMD_AUTO_MODE) != NULL)              // Auto module
    {                                                             //切换后，自动模式会接着前面的状态和计时       
        auto_count_flag = 0;                                      //计时结束后才会从自动模式的初始值开始
        currentMode = SetKeyStatus(TRAFFIC_AUTO_MODE);
        currentType = GetKeyStatus(CURRENT_TYPE);

        Timer_Stra_NS_G_Auto = 10;
        Timer_Stra_NS_Y = 3;
        Timer_Stra_EW_G_Auto = 10;
        Timer_Stra_EW_Y = 3;
    }
}

// /< this is the callback function, set to the mqtt, and if any messages come, it will be called
// /< The payload here is the json string
static void DemoMsgRcvCallBack(int qos, const char *topic, char *payload)
{
    const char *requesID;
    char *tmp;
    IoTCmdResp resp;
    IOT_LOG_DEBUG("RCVMSG:QOS:%d TOPIC:%s PAYLOAD:%s\r\n", qos, topic, payload);
    
    /* app 下发的操作 */
    TrafficLightMsgRcvCallBack(payload);
    tmp = strstr(topic, CN_COMMADN_INDEX);
    if (tmp != NULL) 
    {
        // /< now you could deal your own works here --THE COMMAND FROM THE PLATFORM
        // /< now er roport the command execute result to the platform
        requesID = tmp + strlen(CN_COMMADN_INDEX);
        resp.requestID = requesID;
        resp.respName = NULL;
        resp.retCode = 0;   ////< which means 0 success and others failed
        resp.paras = NULL;
        (void)IoTProfileCmdResp(CONFIG_DEVICE_PWD, &resp);
    }
    return;
}

/* traffic light:1.control module */
void SetupTrflControlModule(HiTrafficLightMode currentMode, HiControlModeType currentType)
{
    IoTProfileService service;
    IoTProfileKV property;
    unsigned char status = 0;

    printf("traffic light:control module\r\n");
    if (currentMode != TRAFFIC_CONTROL_MODE && currentType != STRA_NS_GREEN) 
    {
        printf("select current module is not the TRAFFIC_CONTROL_MODE\r\n");
        return HI_NULL;
    }
    status = SetKeyStatus(TRAFFIC_CONTROL_MODE);
    currentType = GetKeyStatus(CURRENT_TYPE);

    memset_s(&property, sizeof(property), 0, sizeof(property));
    property.type = EN_IOT_DATATYPE_STRING; //回报内容的类型，这里应该是字符串
    property.key = "ControlModule";         //交通灯当前工作模式
    if (currentType == STRA_NS_GREEN) 
    {
            property.value = "STRAIGHT_NORTH_SOUTH_GREEN";  //回报的具体内容
    } 
    else if (currentType == STRA_NS_YELLOW) 
    {
            property.value = "STRAIGHT_NORTH_SOUTH_YELLOW";
    }
    else if (currentType == STRA_EW_GREEN) 
    {
            property.value = "STRAIGHT_EAST_WEST_GREEN";
    }
    else if (currentType == STRA_EW_YELLOW) 
    {
            property.value = "STRAIGHT_EAST_WEST_YELLOW";
    }

    memset_s(&service, sizeof(service), 0, sizeof(service));
    service.serviceID = "TrafficLight";
    service.serviceProperty = &property;
    IoTProfilePropertyReport(CONFIG_DEVICE_ID, &service);

    memset_s(&property, sizeof(property), 0, sizeof(property));
    property.type = EN_IOT_DATATYPE_STRING; //回报内容的类型，这里应该是字符串
    property.key = "AutoModule";
    property.value = "Closed";
    memset_s(&service, sizeof(service), 0, sizeof(service));
    service.serviceID = "TrafficLight";
    service.serviceProperty = &property;
    IoTProfilePropertyReport(CONFIG_DEVICE_ID, &service);

}

/* traffic light:2.auto module */
void SetupTrflAutoModule(HiTrafficLightMode currentMode, HiControlModeType currentType)
{
    IoTProfileService service;
    IoTProfileKV property;
    unsigned char status = 0;

    printf("traffic light:auto module\r\n");
    if (currentMode != TRAFFIC_AUTO_MODE) 
    {
        printf("select current module is not the CONTROL_MODE\r\n");
        return HI_NULL;
    }

    status = SetKeyStatus(TRAFFIC_AUTO_MODE);
    currentType = GetKeyStatus(CURRENT_TYPE);

    memset_s(&property, sizeof(property), 0, sizeof(property));
    property.type = EN_IOT_DATATYPE_STRING; //回报内容的类型，这里应该是字符串
    property.key = "AutoModule";            //交通灯当前工作模式
    if (currentType == STRA_NS_GREEN) 
    {
            property.value = "STRAIGHT_NORTH_SOUTH_GREEN";  //回报的具体内容
    } 
    else if (currentType == STRA_NS_YELLOW) 
    {
            property.value = "STRAIGHT_NORTH_SOUTH_YELLOW";
    }
    else if (currentType == STRA_EW_GREEN) 
    {
            property.value = "STRAIGHT_EAST_WEST_GREEN";
    }
    else if (currentType == STRA_EW_YELLOW) 
    {
            property.value = "STRAIGHT_EAST_WEST_YELLOW";
    }

    memset_s(&service, sizeof(service), 0, sizeof(service));
    service.serviceID = "TrafficLight";
    service.serviceProperty = &property;
    IoTProfilePropertyReport(CONFIG_DEVICE_ID, &service);

    memset_s(&property, sizeof(property), 0, sizeof(property));
    property.type = EN_IOT_DATATYPE_STRING; //回报内容的类型，这里应该是字符串
    property.key = "ControlModule";
    property.value = "Closed";
    memset_s(&service, sizeof(service), 0, sizeof(service));
    service.serviceID = "TrafficLight";
    service.serviceProperty = &property;
    IoTProfilePropertyReport(CONFIG_DEVICE_ID, &service);

}

void TrafficLightStatusReport(HiTrafficLightMode currentMode, const TrflCallBackFunc msgReport)
{
    printf("tarffic light: reporting status...\r\n");
    switch (currentMode) 
    {
        case TRAFFIC_CONTROL_MODE:
            msgReport(TRAFFIC_CONTROL_MODE, NULL);
            break;
        case TRAFFIC_AUTO_MODE:
            msgReport(TRAFFIC_AUTO_MODE, NULL);
            break;
        default:
            break;
    }
    return HI_NULL;
}

static void ReportTrafficLightMsg(void)
{
    switch (GetKeyStatus(CURRENT_MODE)) 
    {
        case TRAFFIC_CONTROL_MODE:
            TrafficLightStatusReport(TRAFFIC_CONTROL_MODE, SetupTrflControlModule);
            break;
        case TRAFFIC_AUTO_MODE:
            TrafficLightStatusReport(TRAFFIC_AUTO_MODE, SetupTrflAutoModule);
            break;
        default:
            break;
    }
}

///< this is the demo main task entry,here we will set the wifi/cjson/mqtt ready ,and
///< wait if any work to do in the while
static void *DemoEntry(const char *arg)
{
    hi_watchdog_disable();
    WifiStaReadyWait();
    CJsonInit();
    printf("cJsonInit init \r\n");
    IoTMain();
    IoTSetMsgCallback(DemoMsgRcvCallBack);
    
/* 主动上报 */
#ifdef TAKE_THE_INITIATIVE_TO_REPORT
    while (1) 
    {
        //< now we report the data to the iot platform
        hi_sleep(TASK_SLEEP_500MS); 
        ReportTrafficLightMsg();

    }
#endif
}

///< This is the demo entry, we create a task here, and all the works has been done in the demo_entry
#define CN_IOT_TASK_STACKSIZE  0x1000
#define CN_IOT_TASK_PRIOR 26
#define CN_IOT_TASK_NAME "IOTDEMO"
static void AppDemoIot(void)
{
    osThreadAttr_t attr;
    IoTWatchDogDisable();

    attr.name = "IOTDEMO";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = CN_IOT_TASK_STACKSIZE;
    attr.priority = CN_IOT_TASK_PRIOR; //优先级26

    if (osThreadNew((osThreadFunc_t)DemoEntry, NULL, &attr) == NULL) 
    {
        printf("[TrafficLight] Falied to create IOTDEMO!\n");
    }
}

SYS_RUN(AppDemoIot);